def get_model_collection_sets(model_class):
    coll_set = []
    for cls in model_class.__mro__:
        if hasattr(cls, '_collection_sets'):
            coll_set.extend(getattr(cls, '_collection_sets'))
    return list(set(coll_set))

def get_model_collections_doc(model_class, indent='', sphinx_doc=False):
    if sphinx_doc:
        coll_str = "%s* :class:`%s <simcat.models.%s>`\n" % (indent, 
                                                             model_class._meta.object_name,
                                                             model_class._meta.object_name)
    else:
        coll_str = "%s%s\n" % (indent, model_class._meta.object_name)
    if hasattr(model_class, '_collection_sets'):
        i = 0
        for collection in get_model_collection_sets(model_class):
            if sphinx_doc and i == 0:
                coll_str += '\n'
            i += 1
            # avoid recursive case from ObjectType
            contained_model = getattr(model_class, collection).related.model
            if collection != 'child_objects' and collection != 'child_collections':
                coll_str += get_model_collections_doc(contained_model,
                                                      indent + '  ', sphinx_doc)
            else:
                if sphinx_doc:
                    coll_str += "%s* :class:`%s <simcat.models.%s>`\n" % (indent + '  ',
                                                                          model_class._meta.object_name,
                                                                          model_class._meta.object_name)
                else:
                    coll_str += "%s%s\n" % (indent + '  ', model_class._meta.object_name)
            if sphinx_doc and i > 0:
                coll_str += '\n'
    return coll_str

def collections_doc(sphinx_doc=False):
    coll_str = ''
    from models import root_elements
    for mdl in root_elements:
        coll_str += get_model_collections_doc(mdl, sphinx_doc=sphinx_doc)

    coll_str = coll_str.replace('\n\n\n', '\n\n')
    return coll_str

def collections_list():
    def model_collections_list(model_class):
        coll_list = [model_class]
        if hasattr(model_class, '_collection_sets'):
            for collection in get_model_collection_sets(model_class):
                contained_model = getattr(model_class, collection).related.model
                if contained_model != model_class:
                    coll_list.extend(model_collections_list(contained_model))
        return coll_list

    collections = []
    from models import root_elements
    for mdl in root_elements:
        collections.extend(model_collections_list(mdl))
    return list(set(collections))

def get_model_doc(cls):
    """Returns ReST summarizing a model's fields and collections."""

    doc_str = cls._meta.object_name +'\n'
    doc_str += '-'*len(cls._meta.object_name) + '\n\n'
    doc_str += '.. autoclass:: simcat.models.%s\n\n' % cls._meta.object_name
    doc_str += '   **Fields**\n\n'
    for field in cls._meta.fields:
        if field.serialize or field.attname == 'id':            
            doc_str += '   .. attribute:: %s' % field.attname
            if field.attname != field.name:
                doc_str += ', %s' % field.verbose_name
            doc_str += '\n\n'
            # Write out using class name, rather than type
            doc_str += '      %s' % field.__class__.__name__
            if field.get_internal_type()  == 'ForeignKey':
                if field.attname == cls._container_field:
                    doc_str += ' (Container)'
                else:
                    doc_str += ' (Reference)'
                doc_str += ' :class:`%s <simcat.models.%s>`' % (field.rel.to._meta.object_name, 
                                                                field.rel.to._meta.object_name)
            doc_str += '\n\n'
            if field.choices:
                doc_str += '      Choices:\n\n'
                for name, description in field.choices:
                    doc_str += '      * %s\n' % name
            doc_str += '\n'
            
    if len(get_model_collection_sets(cls)) > 0:
        doc_str += '   **Collections**\n\n'
        for collection_name in get_model_collection_sets(cls):
            obj_name = getattr(cls, collection_name).related.model._meta.object_name
            doc_str += '   * :class:`%s <simcat.models.%s>`\n' % (obj_name, obj_name)
                
    doc_str += '\n'
    return doc_str
